package com.naiterui.ehp.bs.esign.controller.openapi;

import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.naiterui.ehp.bp.support.advice.IgnoreResponseEntityWrap;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.support.utils.JsonMapper;
import com.naiterui.ehp.bp.utils.beans.BeanUtil;
import com.naiterui.ehp.bs.esign.api.bjca.util.SignYwxUtil;
import com.naiterui.ehp.bs.esign.api.bjca.vo.YwxCallbackHeadVO;
import com.naiterui.ehp.bs.esign.api.bjca.vo.YwxCallbackVO;
import com.naiterui.ehp.bs.esign.api.bjca.vo.YwxResponseVO;
import com.naiterui.ehp.bs.esign.api.bjca.vo.YwxSignCallbackVO;
import com.naiterui.ehp.bs.esign.api.bjca.vo.YwxUserCallbackVO;
import com.naiterui.ehp.bs.esign.api.vo.SignCallbackVO;
import com.naiterui.ehp.bs.esign.exception.ExceptionCodes;
import com.naiterui.ehp.bs.esign.service.IEsignService;

/**
 * <pre>
 *     医网签回调接口
 * </pre>
 *
 * @author guoyongxiang
 * @date 2019/11/23 13:52
 * @since 1.0.0
 */
@RequestMapping("esign/openapi/ywx")
@RestController
public class OpenYwxController {

    private static final Logger LOGGER = LoggerFactory.getLogger(OpenYwxController.class);

    @Autowired
    private IEsignService esignService;

    @IgnoreResponseEntityWrap
    @RequestMapping("result/user")
    public YwxResponseVO user(@RequestBody YwxCallbackVO<YwxUserCallbackVO> callbackVO) throws BusinessException {
        LOGGER.info("医网信用户审核结果回调:{}", callbackVO);
        try {
            YwxUserCallbackVO data = this.verifySign(callbackVO);
            this.esignService.userAuth(data.getOpenId(), data.getPhoneNum(), data.getProcess(), data.getNote());
        } catch (BusinessException e) {
            LOGGER.warn("医网信用户审核结果回调，处理失败, msg:{}", e.getMessage());
            return YwxResponseVO.builder().status(YwxResponseVO.CODE_ERROR).message(e.getMessage()).build();
        } catch (Exception e) {
            LOGGER.error("医网信签名结果回调，处理异常", e);
            return YwxResponseVO.builder().status(YwxResponseVO.CODE_ERROR).message(e.getMessage()).build();
        }
        return YwxResponseVO.builder().status(YwxResponseVO.CODE_SUCCESS).message("success").build();
    }

    @IgnoreResponseEntityWrap
    @RequestMapping("result/sign")
    public YwxResponseVO sign(@RequestBody YwxCallbackVO<YwxSignCallbackVO> callbckVO) {
        LOGGER.info("医网信签名结果回调成功: unionId={}, status={}, body={}", callbckVO.getBody().getUniqueId(), callbckVO.getBody().getStatus(), callbckVO);
        try {
            YwxSignCallbackVO data = this.verifySign(callbckVO);
            SignCallbackVO signCallbackVO = new SignCallbackVO();
            BeanUtil.copyProperties(data, signCallbackVO);
            this.esignService.signResult(signCallbackVO);

        } catch (BusinessException e) {
            LOGGER.warn("医网信签名结果回调，处理失败, msg:{}", e.getMessage());
            return YwxResponseVO.builder().status(YwxResponseVO.CODE_ERROR).message(e.getMessage()).build();
        } catch (Exception e) {
            LOGGER.error("医网信签名结果回调，处理异常", e);
            return YwxResponseVO.builder().status(YwxResponseVO.CODE_ERROR).message(e.getMessage()).build();
        }
        return YwxResponseVO.builder().status(YwxResponseVO.CODE_SUCCESS).message("success").build();
    }

    /**
     * 验签
     *
     * @param callbckVO
     *
     * @throws BusinessException
     */
    private <T> T verifySign(YwxCallbackVO<T> callbckVO) throws BusinessException {
        String sign = Optional.ofNullable(callbckVO).map(YwxCallbackVO::getHead).map(YwxCallbackHeadVO::getSign).orElse(null);
        String json = JsonMapper.toJson(callbckVO.getBody());
        boolean pass = SignYwxUtil.verifySign(json, sign);
        if (!pass) {
            throw new BusinessException(ExceptionCodes.ESIGN_SIGN_NOT_MATCH);
        }
        return callbckVO.getBody();
    }
}
